#include "ThreadPool.h"

nmspc::ThreadPool::~ThreadPool()
{
	{
		std::unique_lock<std::mutex> lock(this->queue_mutex);
		this->stop = true;
	}
	this->wakeup_condition.notify_all();
	for (std::thread& worker : this->workers)
	{
		worker.join();
	}
}

nmspc::ThreadPool::ThreadPool(std::size_t threads_num) :stop(false)
{
	for (std::size_t i = 0; i < threads_num; ++i)
	{
		workers.emplace_back(&ThreadPool::worker, this);
	}
}

void nmspc::ThreadPool::worker()
{
	while (true) 
	{
		std::function<void()> task;
		{
			std::unique_lock<std::mutex> lock(this->queue_mutex);
			this->wakeup_condition.wait(lock, [this] { return this->stop || !this->tasks.empty(); });
			if (this->stop && this->tasks.empty()) return;
			task = std::move(this->tasks.front());
			this->tasks.pop();
		}
		task();
		{
			std::unique_lock<std::mutex> lock(this->queue_mutex);
			this->active_tasks--;
			if (this->tasks.empty() && this->active_tasks == 0)
			{
				this->finished_condition.notify_all();
			}
		}
	}
}

void nmspc::ThreadPool::wait()
{
	std::unique_lock<std::mutex> lock(this->queue_mutex);
	this->finished_condition.wait(lock, [this] {return this->tasks.empty() && this->active_tasks == 0; });
}
